package io.kiki.sba.registry.server.metadata.provide.data;

import io.kiki.sba.registry.server.metadata.MetadataLeaderService;
import io.kiki.sba.registry.server.metadata.bootstrap.config.ServerConfig;
import io.kiki.sba.registry.server.shared.client.manager.BaseClientManagerService;
import io.kiki.sba.registry.store.api.date.DateNowRepository;
import io.kiki.sba.registry.util.ConcurrentUtils;
import io.kiki.sba.registry.util.LoopExecuteTask;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Setter
@Getter
public class DefaultClientManagerService extends BaseClientManagerService implements ApplicationListener<ContextRefreshedEvent> {

    private static final Logger logger = LoggerFactory.getLogger(DefaultClientManagerService.class);
    final Cleaner cleaner = new Cleaner();
    @Autowired
    DateNowRepository dateNowRepository;
    @Autowired
    ServerConfig serverConfig;
    @Setter
    @Autowired
    MetadataLeaderService metadataLeaderService;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        start();
    }

    public void start() {
        ConcurrentUtils.createDaemonThread("clientManagerCleaner", cleaner).start();
        logger.info("ClientManagerCleaner started");
    }

    Date dateBeforeNow(int day) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dateNowRepository.getNow());
        calendar.add(Calendar.DATE, -day);
        return calendar.getTime();
    }


    final class Cleaner extends LoopExecuteTask {

        private final int maxRemoved = 200;

        @Override
        public void _execute_() {
            if (!metadataLeaderService.amIStableAsLeader()) {
                return;
            }

            doCleanExpired();
        }

        private void doCleanExpired() {
            Date date = dateBeforeNow(serverConfig.getClientManagerExpireDays());
            List<String> expireAddress = getClientManagerAddressRepository().getExpireAddress(date, maxRemoved);
            if (CollectionUtils.isNotEmpty(expireAddress)) {
                int count = getClientManagerAddressRepository().cleanExpired(expireAddress);
                logger.info("clean expired address, expect:{}, actual:{}, address:{}", expireAddress.size(), count, expireAddress);
            }

            int expireClientOffSize = getClientManagerAddressRepository().getClientOffSizeBefore(date);
            logger.info("expire client off address size:{}", expireClientOffSize);
        }

        @Override
        public void _wait_() {
            ConcurrentUtils.sleepUninterruptibly(serverConfig.getClientManagerCleanSecs(), TimeUnit.SECONDS);
        }
    }
}
